#include "vcf.h"
#include <QString>
#include <QFile>
#include <QDebug>
#include <QThread>
#include <QByteArray>
#include <QTextCodec>
#include <string.h>

int g_var = 334;
enum KEYTYPE{
    eKEY_N,
    eKEY_FN,
    eKEY_TEL,
    eKEY_NOTE
};

QString encode(const char* pSrc);
QString decode(const QByteArray &qpStr);
int joinNamelist(const QList<VCard>& vcardlist, const QString &tel, QStringList & namelist, QStringList& notelist);
bool isExistTelnumber(const QList<VCard>& vcardlist, const QString &tel);
void removeContain(QStringList &sslist, const QString &strLongname);

QString encode(const char* pSrc)
{
    const int nMaxLineLen = 70;
    char szDst[10240] = {0};
    int nLineLen = 0;
    for (size_t iSrc = 0, iDst = 0; iSrc < strlen(pSrc); iSrc++) {
        // ASCII 33-60, 62-126非原样输出，全部需编码
        if ( false && pSrc[iSrc] >= '!' && pSrc[iSrc] <= '~' && pSrc[iSrc] != '=') {
            szDst[iDst++] = pSrc[iSrc];
            nLineLen++;
        } else {
            sprintf(szDst+iDst, "=%02X", (unsigned char)pSrc[iSrc]);
            iDst += 3;
            nLineLen += 3;
        }
        // 70字截断换行
        if (nLineLen >= nMaxLineLen - 3) {
            sprintf(szDst+iDst, "=\n");   //  \r\n
            iDst += 2;
            nLineLen = 0;
        }
    }
    return QString(szDst);
}

QString decode(const QByteArray &qpStr)
{
    QByteArray dst;
    int i = 0;
    while( i <  qpStr.size()  ){
        if( '=' == qpStr.at(i) ){
            if( "=\r\n" == qpStr.mid(i, 3) ){    // =\r\n
                i += 3;
            }else{
                char ch1 = qpStr.at(i+1);
                char ch2 = qpStr.at(i+2);
                dst += ((ch1>'9')?(ch1-'A'+10):(ch1-'0')) * 16 + ((ch2>'9')?(ch2-'A'+10):(ch2-'0'));
                i += 3;
            }
        } else {
            dst += qpStr[i];
            i++;
        }
    }
    return QTextCodec::codecForName("UTF-8")->toUnicode(dst);
}

int joinNamelist(const QList<VCard>& vcardlist, const QString &tel, QStringList & namelist, QStringList& notelist)
{
    int count = 0;
    foreach (VCard cad, vcardlist) {
        if (cad.tel == tel) {
            namelist << cad.name;
            notelist << cad.note1;
            count++;
        }
    }
    namelist = namelist.toSet().toList();
    notelist = notelist.toSet().toList();
    namelist.removeAll("");
    notelist.removeAll("");
    std::sort(namelist.begin(), namelist.end(), [](const QString &s1, const QString &s2){ return s1.length() > s2.length();} );
    std::sort(notelist.begin(), notelist.end(), [](const QString &s1, const QString &s2){ return s1.length() > s2.length();} );
    return count;
}

bool isExistTelnumber(const QList<VCard>& vcardlist, const QString &tel)
{
    foreach (VCard cad, vcardlist) {
        if (cad.tel == tel) {
            return true;
        }
    }
    return false;
}

void removeContain(QStringList &sslist, const QString &strLongname)
{
    for(int i = 0; i < sslist.count(); ){
        if( strLongname.indexOf(sslist.at(i) ) >=0 ){
            sslist.removeAt(i);
        }else{
            i++;
        }
    }
}

void trimValue(QString &sVal)
{
    sVal = sVal.trimmed();
    sVal.replace("vnd.android.cursor.item/nickname;", "");
    sVal.replace("\\\\\\\\", "\\");
    sVal.replace("\\\\", "\\");
    sVal.replace("\r\n", ";");
    sVal.replace("\n", ";");
    sVal.replace("\\n", ";");
    sVal.replace(";;", ";");
    sVal.replace(";;", ";");
    sVal.replace(";;", ";");
    sVal.replace(";;", ";");
    sVal.replace("手机：", "");
    sVal.replace("名字：", "");
    sVal.replace("，", "#");
    sVal.replace("。", ".");
    while (sVal.startsWith(";")) {
        sVal = sVal.mid(1);
    }
    while (sVal.endsWith(";")) {
        sVal.chop(1);
    }
    sVal = sVal.trimmed();
}

QString trimTel(const QString & sVal)
{
    QString nTel2;
    for(int i = 0; i < sVal.length(); i++){
        if(sVal.at(i).isDigit()){
            nTel2 += sVal.at(i);
        }
    }
    if(nTel2.startsWith("861")){
        nTel2 = nTel2.mid(2);
    }
    return nTel2;
}

QList<VCard> dealVCard(const QList<VCard>& vcardlist1)
{
    // deleteNouse
    QList<VCard> tmplist;
    foreach (VCard cad, vcardlist1) {
        if( cad.name.indexOf("智行火车票") >=0 ||
            cad.name.indexOf("V触宝免费电话") >=0 ||
            cad.name.indexOf("专线电话") >=0 ||
            cad.name.indexOf("钉钉") >=0 ||
            cad.name.indexOf("易信专线") >=0 ||
            cad.name.indexOf("阿里通") >=0 ||
            cad.name.length() == 0){
            continue;
        }
        tmplist << cad;
    }
    // selectMutiple
    QList<VCard> vcardlist2;
    foreach (VCard cad, tmplist) {
        if (isExistTelnumber(vcardlist2, cad.tel)) {
            continue;
        }
        int count = 0;
        QStringList namelist;
        QStringList notelist;
        count = joinNamelist(vcardlist2, cad.tel, namelist, notelist);
        namelist.removeAll(cad.name);
        removeContain(namelist, cad.name);
        removeContain(notelist, cad.name);
        if(count > 1 && namelist.count() > 1) {
            cad.note1 = namelist.join(";");
            if (notelist.count() > 1) {
                cad.note1 += (";"+ notelist.join(";"));
            }
        }
        if(cad.tel.length() == QString("9280000").length() && cad.note1.length() == 0){
            cad.note1 = "海康";
        }
        vcardlist2 << cad;
    }
    return vcardlist2;
}

QList<VCard> parseVCard(const QString & vCard)
{
    //    qDebug() << vCard.length() << vCard << "\n\n";
    QList<VCard> cardlist;
    QString nameCurrent ;
    int nameIndex = 0;
    VCard card;
    for(int i=0; ; ) {
        int posLinefeed = -1;
        QString sLine;
        for (; ;) {
            posLinefeed = vCard.indexOf("\r\n", i);
            if(posLinefeed < 0){
                break;
            }
            QString sTmp = vCard.mid(i, posLinefeed - i + 2);
            sLine += sTmp;
            i = posLinefeed + 2;
            if (sTmp.startsWith("PHOTO;ENCODING=BASE64;JPEG:")) {
                posLinefeed = vCard.indexOf("\r\n\r\n", i);
                if(posLinefeed >= 0){
                    sTmp = vCard.mid(i, posLinefeed - i + 2);
                    sLine += sTmp;
                    i = posLinefeed + 4;
                }
                break;
            }else if(!sTmp.endsWith("=\r\n")) {
                break;
            }
        }
        if(sLine.length() == 0) {
            break;
        }

        KEYTYPE nKey = eKEY_NOTE;
        QString sVal;
        if(sLine.startsWith("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:") ){
            nKey = eKEY_N;
            sVal = sLine.mid(strlen("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:") );
        }else if(sLine.startsWith("FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_FN;
            sVal = sLine.mid(strlen("FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));
        }else if(sLine.startsWith("NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("NOTE;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("NOTE;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("X-ANDROID-CUSTOM;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("X-ANDROID-CUSTOM;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"));

        }else if(sLine.startsWith("PHOTO;ENCODING=BASE64;JPEG:")) {
            nKey = eKEY_NOTE;
            sVal = ""; // sLine.mid(strlen("PHOTO;ENCODING=BASE64;JPEG:"));

        }else if(sLine.startsWith("VERSION:2.1")){
            //            nKey = eKEY_VERSION;
            //            sVal = "2.1";
        }else if(sLine.startsWith("TEL;VOICE:")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;VOICE:"));

        }else if(sLine.startsWith("TEL;WORK:")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;WORK:"));

        }else if(sLine.startsWith("TEL;CELL:")){
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;CELL:"));

        }else if(sLine.startsWith("TEL;HOME:")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;HOME:"));

        }else if(sLine.startsWith("TEL;:")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;:"));

        }else if(sLine.startsWith("TEL;X-")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;X-"));

        }else if(sLine.startsWith("EMAIL;WORK:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("EMAIL;WORK:"));

        }else if(sLine.startsWith("EMAIL;HOME:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("EMAIL;HOME:"));

        }else if(sLine.startsWith("X-ANDROID-CUSTOM:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("X-ANDROID-CUSTOM:"));

        }else if(sLine.startsWith("TEL;CELL;PREF:")) {
            nKey = eKEY_TEL;
            sVal = sLine.mid(strlen("TEL;CELL;PREF:"));

        }else if(sLine.startsWith("BDAY:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("BDAY:"));

        }else if(sLine.startsWith("EMAIL:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("EMAIL:"));

        }else if(sLine.startsWith("X-ANDROID-CUSTOM:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("X-ANDROID-CUSTOM:"));

        }else if(sLine.startsWith("ORG:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("ORG:"));

        }else if(sLine.startsWith("N:")) {
            nKey = eKEY_N;
            sVal = sLine.mid(strlen("N:"));

        }else if(sLine.startsWith("FN:")) {
            nKey = eKEY_FN;
            sVal = sLine.mid(strlen("FN:"));

        }else if(sLine.startsWith("NOTE:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("NOTE:"));

        }else if(sLine.startsWith("URL:")) {
            nKey = eKEY_NOTE;
            sVal = sLine.mid(strlen("URL:"));

        }else {
            qDebug() << sLine;
            QThread::sleep(1);
        }
        sVal = decode(sVal.toUtf8());
        trimValue(sVal);
        if(sVal.length() == 0){
            continue;
        }
        //        qDebug() << sVal;

        switch (nKey) {
        case eKEY_N:
            sVal.replace(";","");
            card.name = sVal;
            break;
        case eKEY_FN:
            sVal.replace(";","");
            if(sVal != card.name){
                qDebug()<<"fullname"<< sVal << card.name;
            }
            break;
        case eKEY_TEL:
        {
            QString sTelv = trimTel(sVal);
            if(card.tel.length() < 2){
                nameCurrent = card.name;
                nameIndex = 0;
                card.tel = sTelv;
            }else{
                cardlist << card;
                card.name = nameCurrent;
                card.tel = sTelv;
                //                qDebug() << "tel:" << card.name <<  card.tel;
            }
        }
        break;

        case eKEY_NOTE:
        default:
            if(card.note1.indexOf(sVal) < 0){
                if(card.note1.isEmpty()){
                    card.note1 += (sVal);
                }else{
                    card.note1 += (";"+sVal);
                }
            }
            break;
        }
    }

    if(card.tel.length() < 2){
        //        qDebug()<<"tel = none" << sci++ << card.tel << card.name << "\t\t" << card.note1;
    }else{
        cardlist << card;
    }
    return cardlist;
}


bool Vcf::Vcf2Csv(const QString &vcfName, const QString &csvFile)
{
    QFile fil(vcfName);
    bool ret = fil.open(QFileDevice::ReadOnly);
    if(!ret) {
        return false;
    }
    QString sContent = fil.readAll();
    QList<VCard> vcardlist;
    int count = 0;
    for (int i=0; ; ) {
        int posBegin = sContent.indexOf("BEGIN:VCARD", i );
        int posEnd = sContent.indexOf("END:VCARD", i );
        if(posBegin < 0 || posEnd < 0){
            break;
        }
        QString vCard = sContent.mid(posBegin, posEnd - posBegin);
        i = posEnd + (int)strlen("END:VCARD");
        vCard.replace("BEGIN:VCARD\r\n", "");
        vCard.replace("END:VCARD\r\n", "");
        vcardlist << parseVCard(vCard);
        count++;
    }
    QList<VCard> listOut = dealVCard(vcardlist);
    qDebug() << "read end. raw count=" << vcardlist.count() << ",deal count=" << count << ",end count=" << listOut.size();
    std::sort(listOut.begin(), listOut.end(), [](const VCard &d1, const VCard &d2) {
        if (d1.name == d2.name) {
            return d1.tel.length() > d2.tel.length();
        }
        return d1.name < d2.name;
    });
    int iDup = 0;
    for (int i = 0; i < listOut.size(); i++) {
        if (i - 1 >= 0 && listOut[i].name == listOut[i-1].name) {
            listOut[i-1].name += ("_" + QString::number(++iDup));
        }else {
            iDup = 0;
        }
    }
    //saveCSV
    sContent.clear();
    foreach (VCard cad, listOut) {
        sContent += cad.name ;
        sContent += "," ;
        sContent += cad.tel;
        sContent += "," ;
        sContent += cad.note1;
        sContent += "\n" ;
    }
    QByteArray  strBytes = sContent.toUtf8().insert(0, "\xEF\xBB\xBF", 3);
    QFile fl(csvFile);
    ret = fl.open(QFileDevice::WriteOnly|QIODevice::Text);
    if(!ret) {
        qDebug()<<"open error"<< csvFile;
        return false;
    }
    fl.write(strBytes, strBytes.length());
    fl.close();
    return true;
}

bool Vcf::Csv2Vcf(const QString &csvName, const QString &vcfFile)
{
    QFile fil(csvName);
    bool ret = fil.open(QFileDevice::ReadOnly);
    if(!ret) {
        return false;
    }
    QString sContent = fil.readAll();
    QList<VCard> cardlist;
    for(int i=0; ;) {
        int posLF = sContent.indexOf("\r\n", i);
        if(posLF < 0){
            break;
        }
        QString sLine = sContent.mid(i, posLF - i);
        i = posLF + 2;
        QStringList words = sLine.split(",");
        if(words.count() < 3){
            qDebug() << "[line]" << words;
            continue;
        }
        cardlist += {words.at(1), words.at(0), words.at(2)};
    }
    //saveVcf
    sContent.clear();
    foreach (VCard cad, cardlist) {
        sContent += "BEGIN:VCARD\n";
        sContent += "VERSION:2.1\n";
        sContent += ("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" + encode(cad.name.toUtf8().data()) + "\n" );
        sContent += ("TEL;CELL:" + cad.tel + "\n" );
        sContent += ("NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:" + encode(cad.note1.toUtf8().data()) + "\n" );
        sContent += ("END:VCARD\n");
    }
    QByteArray strBytes = sContent.toUtf8().insert(0, "\xEF\xBB\xBF", 3);
    QFile fl(vcfFile);
    ret = fl.open(QFileDevice::WriteOnly|QIODevice::Text);
    if(!ret){
        qDebug()<<"open error"<< vcfFile;
        return false;
    }
    fl.write(strBytes, strBytes.length());
    fl.close();
    return true;
}
